package cn.oversky.eom.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.collections.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;

import static cn.oversky.eom.utils.PropertiesUtils.isNull;


public class ReflectionUtils {

    private static String EXPRESSION_ARRAY_SYMBOL = "[";
    /**
     * 循环向上转型, 获     * @param object : 子类对象 
     * @param methodName : 父类中的方法名 
     * @param parameterTypes : 父类中的方法参数类型 
     * @return 父类中的方法对象 
     */  
      
    public static Method getDeclaredMethod(Object object, String methodName, Class<?> ... parameterTypes){  
        Method method = null ;  
          
        for(Class<?> clazz = object.getClass() ; clazz != Object.class ; clazz = clazz.getSuperclass()) {  
            try {  
                method = clazz.getDeclaredMethod(methodName, parameterTypes) ;  
                return method ;  
            } catch (Exception e) {  
                //这里甚么都不能抛出去。  
                //如果这里的异常打印或者往外抛，则就不会进入              
            }  
        }  
          
        return null;  
    }  
      
    /** 
     * 直接调用对象方法, 而忽略修饰符(private, protected, default) 
     * @param object : 子类对象 
     * @param methodName : 父类中的方法名 
     * @param parameterTypes : 父类中的方法参数类型 
     * @param parameters : 父类中的方法参数 
     * @return 父类中方法的执行结果 
     */  
      
    public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,  
            Object [] parameters) {  
        //根据 对象、方法名和对应的方法参数 通过取 Method 对象  
        Method method = getDeclaredMethod(object, methodName, parameterTypes) ;
          
        //抑制Java对方法进行检查,主要是针对私有方法而言  
        method.setAccessible(true) ;  
          
            try {  
                if(null != method) {  
                      
                    //调用object 的 method 所代表的方法，其方法的参数是 parameters  
                    return method.invoke(object, parameters) ;  
                }  
            } catch (IllegalArgumentException e) {  
                e.printStackTrace();  
            } catch (IllegalAccessException e) {  
                e.printStackTrace();  
            } catch (InvocationTargetException e) {
                e.printStackTrace();  
            }  
          
        return null;  
    }  
  
    /** 
     * 循环向上转型, 获     * @param object : 子类对象 
     * @param fieldName : 父类中     * @return 父类中     */  
      
    public static Field getDeclaredField(Object object, String fieldName){
        Field field = null ;  
          
        Class<?> clazz = object.getClass() ;  
          
        for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {  
            try {  
                field = clazz.getDeclaredField(fieldName) ;  
                return field ;  
            } catch (Exception e) {  
                //这里甚么都不能抛出去。  
                //如果这里的异常打印或者往外抛，则就不会进入                  
            }   
        }  
      
        return null;  
    }     
      
    /** 
     * 直接设置对象属性值, 忽略 private/protected 修饰符, 也     * @param object : 子类对象 
     * @param fieldName : 父类中     * @param value : 将要设置的值 
     */  
      
    public static void setFieldValue(Object object, String fieldName, Object value){  
      
        //根据 对象和属性名通过取 Field对象  
        Field field = getDeclaredField(object, fieldName) ;  
          
        //抑制Java对其的检查  
        field.setAccessible(true) ;  
          
        try {  
            //将 object 中 field 所代表的值 设置为 value  
             field.set(object, value) ;  
        } catch (IllegalArgumentException e) {  
            e.printStackTrace();  
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        }  
          
    }  
      
    /** 
     * 直接读的属性值, 忽略 private/protected 修饰符, 也     * @param object : 子类对象 
     * @param fieldName : 父类中     * @return : 父类中     */  
      
    public static Object getFieldValue(Object object, String fieldName){
        String[] split = fieldName.split("\\.");
        Queue<String> concurrentLinkedQueue = new ConcurrentLinkedQueue(Arrays.asList(split));
        //根据 对象和属性名通过取 Field对象
        return getFieldValue( object, concurrentLinkedQueue );
    }

    public static class Null {}

    public static Object getFieldValue( Object object, Queue<String> expression ) {
        if( ReflectionUtils.fieldsAllNull( object ) ) {
            return new Null();
        }
        String field = expression.poll();
        Class<?> dataClz = object.getClass();
        try {
            // 如果属性是集合，则使用集合的处理方式
            if( field.contains(EXPRESSION_ARRAY_SYMBOL)) {
                int objIdx = Integer.parseInt(field.replaceAll("^.*\\[", "").replaceAll("].*", ""));
                int i = field.indexOf(EXPRESSION_ARRAY_SYMBOL);
                String newFieldName = field.substring(0, i);
                String getterName = parGetName(newFieldName);
                Method getter = dataClz.getMethod(getterName);
                Collection fieldValueList = (Collection)getter.invoke(object);
                if( isNull( fieldValueList) ) {
                    return new Null();
                }
                int size = fieldValueList.size();
                if( objIdx < size  ) {
                    Object o = CollectionUtils.get(fieldValueList, objIdx);
                    return getFieldValue( o, expression );
                } else {
                    return new Null();
                }
            } else {
                String getterName = parGetName(field);
                Method getter = dataClz.getMethod(getterName);
                Object o = getter.invoke(object);
                if( expression.size() == 0 ) {
                    return o;
                } else {
                    return getFieldValue( o, expression );
                }
            }
        } catch (Exception e) {
            return new Null();
        }
    }


    public static boolean fieldsAllNull(Object bean) {
        boolean result = true;
        if (bean == null) {
            return true;
        }
        Class<?> cls = bean.getClass();
        Method[] methods = cls.getDeclaredMethods();
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            try {
                String fieldGetName = parGetName(field.getName());
                if (!checkGetMet(methods, fieldGetName)) {
                    continue;
                }
                Method fieldGetMet = cls.getMethod(fieldGetName, new Class[]{});
                Object fieldVal = fieldGetMet.invoke(bean, new Object[]{});
                if (fieldVal != null) {
                    if ("".equals(fieldVal)) {
                        result = result && true;
                    } else {
                        result = result && false;
                    }
                }
            } catch (Exception e) {
                continue;
            }
        }
        return result;
    }

    /**
     * 拼接某属性的 get方法
     *
     * @param fieldName
     * @return String
     */
    public static String parGetName(String fieldName) {
        if (null == fieldName || "".equals(fieldName)) {
            return null;
        }
        int startIndex = 0;
        if (fieldName.charAt(0) == '_') {
            startIndex = 1;
        }
        return "get"
                + fieldName.substring(startIndex, startIndex + 1).toUpperCase()
                + fieldName.substring(startIndex + 1);
    }

    /**
     * 判断是否存在某属性的 get方法
     *
     * @param methods
     * @param fieldGetMet
     * @return boolean
     */
    public static boolean checkGetMet(Method[] methods, String fieldGetMet) {
        for (Method met : methods) {
            if (fieldGetMet.equals(met.getName())) {
                return true;
            }
        }
        return false;
    }

    public static void removeEmptyList(List list) {
        if( list == null ) {
            return;
        }
        for( int i = list.size() - 1 ; i >= 0  ; i--) {
            Object ele = list.get(i);
            if( fieldsAllNull( ele ) ) {
                list.remove( ele );
            } else {
                Field[] declaredFields = ele.getClass().getDeclaredFields();
                for( Field field : declaredFields ) {
                    field.setAccessible( true );
                    Object o = null;
                    try {
                        o = field.get(ele);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    if( o instanceof List ) {
                        removeEmptyList((List) o);
                    }
                    field.setAccessible( false );
                }
            }

        }
    }

    /**
     * 根据提供的类，动态创建复杂对象。所有的值都是空的
     * @param clz
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static Object newInstance( Class clz ) throws IllegalAccessException, InstantiationException {
        Object result = clz.newInstance();
        Field[] declaredFields = clz.getDeclaredFields();
        for( Field filed : declaredFields ) {
            Class<?> type = filed.getType();
            Object o = null;
            if( type.getPackage().getName().equals( "java.util" ) ) {
                o = type.equals( List.class )? new ArrayList()
                        : type.equals( Set.class ) ? new HashSet()
                        : type.equals( Map.class )? new HashMap()
                        : null;
            } else if( type.getPackage().getName().equals( "java.lang" ) ) {
                // 对 lang 包的类不做处理
            } else {
                o = type.newInstance();
            }
            filed.setAccessible( true );
            filed.set( result, o );
            filed.setAccessible( false );
        }
        return result;
    }

}